//
//  HACLineRenderer.m
//  Pods
//
//  Created by Hotacool on 2017/8/30.
//
//

#import "HACLineRenderer.h"
#import "HACBasicComponents.h"
#import "HACLineProvider.h"
#import "HACChartUtils.h"
@implementation HACLineRenderer

- (void)drawInRect:(CGRect)rect context:(CGContextRef)context {
    NSArray *datas;
    if ([self.provider conformsToProtocol:@protocol(HACLineProvider)]) {
        id<HACLineProvider> provider = self.provider;
        datas = [provider lineDatasInRect:rect];
    }
    for (HACLineComponents *lineItem in datas) {
        //线绘制线图，再根据是否有填充颜色，绘制填充图
        CGPoint *points = lineItem.linePoints;
        NSMutableArray *pointsArray = lineItem.pointArray;
        if (pointsArray.count > 0) {
            CGContextSetStrokeColorWithColor(context, lineItem.lineColor.CGColor);
            CGContextSetLineWidth(context, lineItem.lineBolder);
            
            // 处理虚线
            CGContextSetLineDash (context, 0, 0, 0);
            if (lineItem.dashLengths) {// 如果需要虚线
                NSInteger count = [lineItem.dashLengths count];
                CGFloat lenghts[count];
                for (int i = 0; i < count; i ++) {
                    lenghts[i]  = [[lineItem.dashLengths objectAtIndex:i] floatValue];
                }
                CGContextSetLineDash(context, 0, lenghts, count);
            }
            
            NSInteger pointCount = pointsArray.count;
            //分段
            NSArray <NSArray*>*subPoints = [self subPointsFromArray:pointsArray];
            if (points != NULL && !lineItem.isCurve && !lineItem.hasInvaildValue) {
                //如果不需要曲线并且不存在kDrawingInvaildValue，直接绘制
                CGContextAddLines(context, points, pointCount);
            } else {
                if (subPoints) {
                    [subPoints enumerateObjectsUsingBlock:^(NSArray * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                        [self drawPoints:obj isCurve:lineItem.isCurve isGradient:NO fillColor:nil InRect:rect context:context];
                    }];
                    CGContextStrokePath(context);
                }
            }
            // 再绘制填充图
            if (lineItem.fillColor) {
                // 分时图设置为填充
                CGContextSetStrokeColorWithColor(context, [UIColor clearColor].CGColor);
                CGContextSetLineWidth(context, 1);
                CGContextSetFillColorWithColor(context, lineItem.fillColor.CGColor);
                if (subPoints) {
                    [subPoints enumerateObjectsUsingBlock:^(NSArray * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                        [self drawPoints:pointsArray isCurve:lineItem.isCurve isGradient:lineItem.isGradient fillColor:lineItem.fillColor InRect:rect context:context];
                    }];
                    CGContextDrawPath(context, kCGPathFillStroke);
                }
            }
        }
    }
}

#define POINT(_INDEX_) (CGPointFromString(points[_INDEX_]))
- (NSArray<NSArray*>*)subPointsFromArray:(NSArray*)points {
    NSMutableArray *subPoints;
    if (points && points.count > 0) {
        subPoints = [NSMutableArray array];
        NSMutableArray *temp;
        CGPoint lastPoint = CGPointMake(kDrawingInvaildValue, kDrawingInvaildValue); // 用于第一个值的判断
        for (int i = 0; i < points.count; i++) {
            CGPoint p = POINT(i);
            if (p.y == kDrawingInvaildValue) {
                // 无效值直接忽略
                if (lastPoint.y != kDrawingInvaildValue) {
                    if (temp) {
                        [subPoints addObject:temp];
                    }
                    temp = nil;
                } else {
                    continue;
                }
            } else {
                if (lastPoint.y == kDrawingInvaildValue) {
                    temp = [NSMutableArray array];
                }
                [temp addObject:NSStringFromCGPoint(p)];
            }
            if (i == points.count-1) {
                if (temp) {
                    [subPoints addObject:temp];
                }
            }
            lastPoint = p;
        }
    }
    return subPoints;
}

- (void)drawPoints:(NSArray*)pointsArray
           isCurve:(BOOL)isCurve
        isGradient:(BOOL)isGradient
         fillColor:(UIColor*)fillColor
            InRect:(CGRect)rect
           context:(CGContextRef)context {
    if (pointsArray.count > 0) {
        NSInteger granularity = 0;
        if (isCurve) { //替换平滑曲线算法: Centripetal Catmull–Rom spline
            granularity = 20;
        }
        UIBezierPath *smoothedPath = [UIBezierPath bezierPath];
        { // 平滑曲线方法
            if (smoothedPath) {
                NSMutableArray *points = [pointsArray mutableCopy];
                
                // Add control points to make the math make sense
                [points insertObject:[points objectAtIndex:0] atIndex:0];
                [points addObject:[points lastObject]];
                
                CGPoint lastPoint = CGPointMake(kDrawingInvaildValue, kDrawingInvaildValue); // 用于第一个值的判断
                for (NSUInteger index = 1; index < points.count - 2; index++) {
                    CGPoint p0 = POINT(index - 1);
                    CGPoint p1 = POINT(index);
                    CGPoint p2 = POINT(index + 1);
                    CGPoint p3 = POINT(index + 2);
                    if (p0.y == kDrawingInvaildValue || p1.y == kDrawingInvaildValue || p2.y == kDrawingInvaildValue || p3.y == kDrawingInvaildValue) {
                        // 无效值直接忽略
                        lastPoint = p1;
                        continue;
                    } else {
                        if (lastPoint.y == kDrawingInvaildValue) {
                            // 说明是第一个有效值（无论是前面有无效值，还是就第一个值）
                            if (fillColor) {//第一个点
                                CGPoint pOrigin = CGPointMake(p0.x, rect.size.height);//接地
                                [smoothedPath moveToPoint:pOrigin];
                                [smoothedPath addLineToPoint:p0];
                            } else {
                                [smoothedPath moveToPoint:p0];
                            }
                        }
                        // 继续绘制后面的点
                        // now add n points starting at p1 + dx/dy up until p2 using Catmull-Rom splines
                        for (int i = 1; i < granularity; i++) {
                            
                            float t = (float) i * (1.0f / (float) granularity);
                            float tt = t * t;
                            float ttt = tt * t;
                            
                            CGPoint pi; // intermediate point
                            pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt);
                            pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt);
                            [smoothedPath addLineToPoint:pi];
                        }
                        
                        // Now add p2
                        [smoothedPath addLineToPoint:p2];
                        lastPoint = p1;
                    }
                }
                
                // finish by adding the last point
                if (fillColor) {//最后一点
                    CGPoint pOrigin = CGPointMake(POINT(points.count - 1).x, rect.size.height);//接地
                    [smoothedPath addLineToPoint:pOrigin];
                } else {
                    [smoothedPath addLineToPoint:POINT(points.count - 1)];
                }
            }
        }
        CGContextAddPath(context, smoothedPath.CGPath);
        
        if (isGradient) {
            [HACChartUtils drawLinearGradient:context path:smoothedPath.CGPath startColor:fillColor.CGColor endColor:[UIColor whiteColor].CGColor];
        }
        
        // 注：老画图方法， 曲线平滑问题，点对不准
        //        NSInteger pointCount = pointsArray.count;
        //        CGPoint lastPoint = CGPointMake(kDrawingInvaildValue, kDrawingInvaildValue); // 用于第一个值的判断
        //        for (int index = 0; index < pointCount; index ++) {
        //            CGPoint point = CGPointFromString(pointsArray[index]);
        //            if (point.y == kDrawingInvaildValue) {
        //                // 无效值直接忽略
        //                lastPoint = point;
        //                continue;
        //            } else {
        //                if (lastPoint.y == kDrawingInvaildValue) {
        //                    // 说明是第一个有效值（无论是前面有无效值，还是就第一个值）
        //                    CGContextMoveToPoint(context, point.x, point.y);
        //                } else {
        //                    // 继续绘制后面的点
        //                    if (isCurve && index < pointCount - 1) {
        //                        // 如果需要曲线并且不是最后一个点
        //                        // 根据当前点，下一个点绘制贝塞尔曲线
        //                        CGPoint nextPoint = CGPointFromString(pointsArray[index + 1]);
        //                        CGContextAddQuadCurveToPoint(context, point.x, point.y, (point.x + nextPoint.x) / 2, (point.y + nextPoint.y) / 2);
        //                    } else {
        //                        // 最后一点直接绘制直线
        //                        CGContextAddLineToPoint(context, point.x, point.y);
        //                    }
        //                }
        //                lastPoint = point;
        //            }
        //        }
    }
}
@end
